﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using T4Template.Dal;
using T4Template.Dto;
using T4Template.Entities;
using T4Template.Model;
using TemplateManager;

namespace T4Template.Bl
{
    class CodeGenerateBL
    {
        private CodeTemplateDal dal;

        public CodeGenerateBL()
        {
            dal = CodeTemplateDal.GetInstance();
        }

        public ActionResultDto<CodeTemplateDto> Generate(GenerateCodeDto dto)
        {
            ActionResultDto<CodeTemplateDto> resultDto = new ActionResultDto<CodeTemplateDto>();
            try
            {
                SearchCriteria criteria = new SearchCriteria();
                criteria.CodeType = dto.CodeType;
                criteria.PatternType = dto.PatternType;
                CodeTemplate foundTemplate = dal.Get(criteria);
                if (foundTemplate == null)
                {
                    throw (new Exception("Error : Found null Template"));
                }
                resultDto.Status = GenerateCode(dto.ClassModel, dto.project, foundTemplate, dto.ToDirectory, dto.FolderTemplate);

                ComplexTemplate t = new ComplexTemplate();
                t.ProjectPath = dto.StartupProjectDirectory;
                IProject p = t.CreateNewProject(dto.SolutionName, dto.CompleteProjectDirectory,
                                                dto.DalProjectName, dto.BlProjectName, dto.MvcProjectName);
                p.AddFile(dto.ToDirectory);
            }
            catch (Exception ex)
            {
                resultDto.Status = false;
                resultDto.ErrorMessage = ex.Message;
            }

            return resultDto;
        }

        //private bool GenerateCode(List<ClassModelDto> classModel, CodeTemplate tempaleDto, String toDirectory)
        //{
        //    bool result = true;

        //    List<string> nsList = tempaleDto.TemplateNameSpaceList;



        //    Assembly assembly = Assembly.GetExecutingAssembly();
        //    foreach (string ns in nsList)
        //    {               
        //        Type[] typelist = assembly.GetTypes().Where(t => String.Equals(t.Namespace, ns, StringComparison.Ordinal)).ToArray();
        //        foreach (Type t in typelist)
        //        {
        //            try
        //            {
        //                dynamic codeObject = Activator.CreateInstance(t);
        //                codeObject.ClassModel = classModel;
        //                String code = GetGenerateCode(codeObject);
        //                if (code != null)
        //                {
        //                    WriteToFile(code, toDirectory, codeObject.GetFilePath());
        //                }
        //            }
        //            catch (Exception ex)
        //            {
        //            }
        //        }
        //    }

        //    List<string> cnList = tempaleDto.TemplateClassNameList;
        //    foreach (string cn in cnList)
        //    {              
        //        try
        //        {
        //            Type classTpe = Type.GetType(cn);
        //            dynamic codeObject = Activator.CreateInstance(classTpe);
        //            codeObject.ClassModel = classModel;
        //            String code = GetGenerateCode(codeObject);
        //            if (code == null)
        //            {
        //                throw (new Exception("Generate Code is null"));
        //            }
        //            WriteToFile(code, toDirectory, codeObject.GetFilePath());
        //        }
        //        catch (Exception ex)
        //        {
        //            result = false;
        //            Console.Write("Generate Error from " + cn + " : " + ex.Message);
        //        }
        //    }

        //    return result;
        //}

        private bool GenerateCode(List<ClassModelDto> classModel, T4Template.Dto.ProjectDto project, CodeTemplate tempaleDto, String toDirectory, String folderTemplate)
        {
            if (classModel == null)
                return false;
            bool result = true;

            List<GenTemplateNameSpace> nsList = tempaleDto.TemplateNameSpaceList;



            Assembly assembly = Assembly.GetExecutingAssembly();
            foreach (var item in nsList)
            {
                try
                {
                    if (item.ns.StartsWith(@".Dal"))
                    {
                        GenerateCodeDal(classModel, project, toDirectory, folderTemplate, item);
                    }
                    else if (item.ns.StartsWith(@".Bl"))
                    {
                        GenerateCodeBl(classModel, project, toDirectory, folderTemplate, item);
                    }
                    else if (item.ns.StartsWith(@".WebApplication"))
                    {
                        GenerateCodeWeb(classModel, project, toDirectory, folderTemplate, item);
                    }

                }
                catch (Exception)
                {

                }
            }

            return result;
        }

        private void GenerateCodeWeb(List<ClassModelDto> classModel, T4Template.Dto.ProjectDto project, String toDirectory, String folderTemplate, GenTemplateNameSpace gt)
        {
            DirectoryInfo d = new DirectoryInfo(folderTemplate + gt.ns.Replace(@".", @"\"));
            string filePath = @"\" + project.Name + gt.ns.Replace("WebApplication", "Web");
            var obj = d.GetFiles("*.cs").Where(t => !t.FullName.ToLower().Contains("partial")).ToArray();
            foreach (var file in obj)
            {
                string pathNamespace = gt.ns.Replace(@"\", @".") + "." + file.Name.Replace(".cs", "");
                string fileName = file.Name;
                Type objType = Type.GetType("T4Template.Template" + pathNamespace.Replace(@" ", @"_"));
                if (fileName.ToLower().Contains("assembly"))
                {
                    GenerateBase(classModel[0], project, toDirectory, gt.ns, filePath + @"\" + fileName, objType);
                }
                else if (fileName.ToLower().Equals("config.cs"))
                {
                    fileName = fileName.Replace("config.cs", "Web.config");
                    GenerateBase(classModel[0], project, toDirectory, gt.ns, filePath + @"\" + fileName, objType);
                }
                else if (fileName.ToLower().Equals("_layout"))
                {
                    GenerateBase(classModel, project, toDirectory, gt.ns, filePath + @"\" + fileName, objType);
                }
                else
                {
                    foreach (var item in classModel)
                    {
                        if (pathNamespace.Contains("Service References"))
                        {
                            fileName = fileName.Replace(@".cs", "");
                            fileName = fileName.Replace(@"_", @".");

                            filePath = @"\" + project.Name + gt.ns.Replace("WebApplication", "Web") + @"\" + item.Name;
                            GenerateBase(item, project, toDirectory, gt.ns, filePath + @"Service\" + item.Name + fileName, objType);
                        }
                        else
                        {
                            if (gt.gen)
                                filePath = @"\" + project.Name + gt.ns.Replace("WebApplication", "Web") + @"\" + item.Name;
                            GenerateBase(item, project, toDirectory, gt.ns, filePath + @"\" + item.Name + fileName, objType);
                        }
                    }
                }
            }
        }

        private void GenerateCodeBl(List<ClassModelDto> classModel, T4Template.Dto.ProjectDto project, String toDirectory, String folderTemplate, GenTemplateNameSpace gt)
        {
            DirectoryInfo d = new DirectoryInfo(folderTemplate + gt.ns.Replace(@".", @"\"));
            string filePath = @"\" + project.Name + gt.ns.Replace("Bl", "Service");
            var obj = d.GetFiles("*.cs").Where(t => !t.FullName.ToLower().Contains("partial")).ToArray();
            foreach (var file in obj)
            {
                string pathNamespace = gt.ns.Replace(@"\", @".") + "." + file.Name.Replace(".cs", "");
                string fileName = file.Name;
                Type objType = Type.GetType("T4Template.Template" + pathNamespace);
                if (fileName.ToLower().Contains("assembly"))
                {
                    GenerateBase(classModel[0], project, toDirectory, gt.ns, filePath + @"\" + fileName, objType);
                }
                else if (fileName.ToLower().Equals("config.cs"))
                {
                    fileName = fileName.Replace("config.cs", "Web.config");
                    GenerateBase(classModel[0], project, toDirectory, gt.ns, filePath + @"\" + fileName, objType);
                }
                else
                {
                    foreach (var item in classModel)
                    {
                        if (fileName.EndsWith("Service_svc.cs"))
                        {
                            fileName = fileName.Replace("Service_svc.cs", "Service.svc");
                        }
                        else if(fileName.EndsWith("Service_svc_cs.cs"))
                        {
                            fileName = fileName.Replace("Service_svc_cs.cs", "Service.svc.cs");
                        }
                        if (gt.gen)
                            filePath = @"\" + project.Name + gt.ns.Replace("Bl", "Service") + @"\" + item.Name;
                        GenerateBase(item, project, toDirectory, gt.ns, filePath + @"\" + item.Name + fileName, objType);
                    }
                }
            }
        }

        private void GenerateCodeDal(List<ClassModelDto> classModel, T4Template.Dto.ProjectDto project, String toDirectory, String folderTemplate, GenTemplateNameSpace gt)
        {
            DirectoryInfo d = new DirectoryInfo(folderTemplate + gt.ns.Replace(@".", @"\"));
            string filePath = @"\" + project.Name + gt.ns;
            var obj = d.GetFiles("*.cs").Where(t => !t.FullName.ToLower().Contains("partial")).ToArray();
            foreach (var file in obj)
            {
                string pathNamespace = gt.ns.Replace(@"\", @".") + "." + file.Name.Replace(".cs", "");
                string fileName = file.Name;
                Type objType = Type.GetType("T4Template.Template" + pathNamespace);
                if (fileName.ToLower().Contains("entities"))
                {
                    foreach (var item in classModel)
                    {
                        if (gt.gen)
                            filePath = @"\" + project.Name + gt.ns + @"\" + item.Name;
                        GenerateBase(item, project, toDirectory, gt.ns, filePath + @"\" + item.Name + ".cs", objType);
                    }
                }
                else if (fileName.ToLower().Contains("assembly"))
                {
                    GenerateBase(classModel[0], project, toDirectory, gt.ns, filePath + @"\" + fileName, objType);
                }
                else
                {
                    foreach (var item in classModel)
                    {
                        if (gt.gen)
                            filePath = @"\" + project.Name + gt.ns.Replace("Bl", "Service") + @"\" + item.Name;
                        GenerateBase(item, project, toDirectory, gt.ns, filePath + @"\" + item.Name + fileName, objType);
                    }
                }
            }
        }

        private void GenerateBase(ClassModelDto classModel, T4Template.Dto.ProjectDto project, String toDirectory, string ns, string fileName, Type objType)
        {
            dynamic codeObject = Activator.CreateInstance(objType);
            codeObject.ClassModel = classModel;
            codeObject.Project = project;
            String code = GetGenerateCode(codeObject);
            if (code != null)
            {
                WriteToFile(code, toDirectory, fileName);
            }
        }
        private void GenerateBase(List<ClassModelDto> classModel, T4Template.Dto.ProjectDto project, String toDirectory, string ns, string fileName, Type objType)
        {
            dynamic codeObject = Activator.CreateInstance(objType);
            codeObject.ClassModel = classModel;
            codeObject.Project = project;
            String code = GetGenerateCode(codeObject);
            if (code != null)
            {
                WriteToFile(code, toDirectory, fileName);
            }
        }
        private string GetGenerateCode(dynamic codeObject)
        {
            string resultCode = null;

            try
            {
                resultCode = codeObject.TransformText();
            }
            catch (Exception ex)
            {
                Console.Write("Generate Error from " + codeObject.GetFilePath() + " : " + ex.Message);
            }

            return resultCode;
        }

        private bool WriteToFile(string code, string toDirectory, string toFile)
        {
            bool resultCode = false;
            string filePath = toDirectory + "\\" + toFile;
            try
            {
                string destDirectory = Path.GetDirectoryName(filePath);
                System.IO.Directory.CreateDirectory(destDirectory);
                if (File.Exists(filePath))
                {
                    File.Delete(filePath);
                }
                System.IO.StreamWriter file = new System.IO.StreamWriter(filePath);
                file.WriteLine(code);
                file.Close();

                resultCode = true;
            }
            catch (Exception ex)
            {
                Console.Write("Write Error from " + filePath + " : " + ex.Message);
            }

            return resultCode;
        }
    }
}
